using NUnit.Framework;
using Tycho.Grammar;

namespace Tycho.UnitTests.Grammar {
    [TestFixture]
    public class CaptureCounterSpecification {
        [Test]
        public void FirstTimeShouldNotCount () {
            var counter = new CaptureCounter ();

            counter.Add ("a");
            counter.Add ("b");

            Assert.That (counter.MultipleCaptures, Is.EquivalentTo (new string[0]));
        }

        [Test]
        public void SecondShouldCount () {
            var counter = new CaptureCounter ();

            counter.Add ("a");
            counter.Add ("b");
            counter.Add ("c");

            counter.Add ("a");
            counter.Add ("b");

            Assert.That (counter.MultipleCaptures, Is.EquivalentTo (new [] {"a", "b"}));
        }

        [Test]
        public void MultipleCaptureCounterShouldCaptureEverythingAsMultiple () {
            var singleCounter = new CaptureCounter ();
            ICaptureCounter multipleCounter = singleCounter.CreateMultipleCaptureScope ();

            multipleCounter.Add ("a");
            multipleCounter.Add ("b");

            Assert.That (multipleCounter.MultipleCaptures, Is.EquivalentTo (new [] {"a", "b"}));
            Assert.That (singleCounter.MultipleCaptures, Is.EquivalentTo (new [] {"a", "b"}));
        }

        [Test]
        public void FirstAndLast () {
            var counter = new CaptureCounter ();
            AssertFirstAndLastBehaviour (counter, counter);
        }

        [Test]
        public void FirstAndLastWithMultiple () {
            var counter = new CaptureCounter ();
            AssertFirstAndLastBehaviour (counter.CreateMultipleCaptureScope (), counter);
        }

        private void AssertFirstAndLastBehaviour (ICaptureCounter forAdding, ICaptureCounter forTesting) {
            FirstAddShouldMakeFirstCapture (forAdding, forTesting);
            SubsequentAddsShouldNotChangeFirstCapture (forAdding, forTesting);
            FirstAddShouldMakeLastCapture (forAdding, forTesting);
            SubsequentAddsShouldMakeLastCapture (forAdding, forTesting);
        }

        public void FirstAddShouldMakeFirstCapture (ICaptureCounter forAdding, ICaptureCounter forTesting) {
            forAdding.Add ("one");

            Assert.That (forTesting.FirstCapture, Is.EqualTo ("one"));
        }

        public void SubsequentAddsShouldNotChangeFirstCapture (ICaptureCounter forAdding, ICaptureCounter forTesting) {
            forAdding.Add ("one");
            forAdding.Add ("two");

            Assert.That (forTesting.FirstCapture, Is.EqualTo ("one"));
        }

        public void FirstAddShouldMakeLastCapture (ICaptureCounter forAdding, ICaptureCounter forTesting) {
            forAdding.Add ("one");

            Assert.That (forTesting.LastCapture, Is.EqualTo ("one"));
        }

        public void SubsequentAddsShouldMakeLastCapture (ICaptureCounter forAdding, ICaptureCounter forTesting) {
            forAdding.Add ("one");
            forAdding.Add ("two");

            Assert.That (forTesting.LastCapture, Is.EqualTo ("two"));
        }
    }
}